<?php
/**
 * ApiController class.
 * ApiController is to base class for API REST.
 * 
 * LBB Solutions Ltd. 版权所有 @ 2012.
 */
class ApiController extends CController
{
	public function actionError() {
		$error = Yii::app()->errorHandler->error;
		if ($error) {
			$this->_sendJSON($error['code'], $error['message']);
		}
	}
	
	/**
	 * Get the recent day name: today, tomorrow, Tus.
	 * @param string $weekdays 1,2,3,4,5,6,7
	 * @return string
	 */
	protected static function GetRecentDayName($weekdays, $week_string, $next24, $start_hour) {
		$today_lbl = BUtils::T('today_lbl');
		$tomorrow_lbl = BUtils::T('tomorrow_lbl');
		
		$today_weekno = date('N');
		$tomorrow_weekno = $today_weekno + 1;
		if ($today_weekno == 7) $tomorrow_weekno = 1;
		
		if ($next24) {
			if ($start_hour > date('Hi')) {// the start hour is coming
				$ipos = strpos($weekdays, $today_weekno);
				if ($ipos !== false) {
					return $today_lbl;//find today
				} else {
					$ipos = strpos($weekdays, (string)$tomorrow_weekno);
					if ($ipos !== false) {
						return $tomorrow_lbl;//find tomorrow
					}
				}
			} else {
				$ipos = strpos($weekdays, (string)$tomorrow_weekno);
				if ($ipos !== false) {
					return $tomorrow_lbl;//find tomorrow
				}
			}
		} else {
			$ipos = strpos($weekdays, $today_weekno);
			if ($ipos !== false) {
				return $today_lbl;//find today
			} else {
				$ipos = strpos($weekdays, (string)$tomorrow_weekno);
				if ($ipos !== false) {
					return $tomorrow_lbl;//find tomorrow
				}
			}
		}
		//return week days string
		return $week_string;
	}
	
	/**
	 * Return string with weekdays.
	 * @param string $weekdays 1,2,3 | 1,2,3,4,5 | 3,4 | 5
	 */
	protected static function GetWeekdays($weekdays, $week_array) {
		$array = explode(',', $weekdays);
		
		//only one day here
		if (count($array) == 1) {
			if (isset($week_array[$array[0]])) {
				return $week_array[$array[0]];
			} else {
				return null;
			}
		}
		
		//check if there is no break day
		$isbreak = false;
		$begin = $array[0];
		foreach ($array as $day) {
			if ($begin != $day) {
				$isbreak = true;
				break;
			}
			$begin ++;
		}
		$selected_days = null;
		if ($isbreak) {
			foreach ($array as $day) {
				if (isset($week_array[$day])) $selected_days .= "{$week_array[$day]} ";
			}
		} else {
			$selected_days = $week_array[$array[0]] . ' - ' . $week_array[$array[count($array)-1]];
		}
		
		return trim($selected_days);
	}

	/**
	 * Logging the values. /../APILogs/api_none_201112.log
	 * @param string $key
	 * @param array $values
	 */
	protected static function APILogging($key, $values, $prefix = 'none') {
		$prefix = str_replace('/', '_', $prefix);	//base64 chars fix for the invalid file name.
		$log = new BLogger(Yii::app()->basePath . "/../APILogs/api_{$prefix}_" . date('Ym') . ".txt", BLogger::INFO);
		$log->LogInfo("{{$key}} -> " . json_encode($values));
	}
	
	/**
	 * Logging the values. /../APILogs/crash/crash_log_none_20130114.log
	 * @param string $key
	 * @param array $values
	 */
	protected static function APICrashing($values, $file_name) {
		$log = new BLogger(Yii::app()->basePath . "/../APILogs/crash/" . $file_name, BLogger::INFO);
		$log->LogInfo($values);
	}
	
	protected function beforeAction($action) {
		//always set language
		$lang = Yii::app()->request->getParam('lang', null);
		if (!empty($lang)) {
			if (Yii::app()->language !== $lang) {
				BUtils::SetLanguage($lang);
			}
		}
		
		//get device, token, reg_id, lat, lng, hid, key
		$device = Yii::app()->request->getParam('device');
		$token = Yii::app()->request->getParam('token');
		if (!empty($device) and !empty($token)) {
			$lat = Yii::app()->request->getParam('lat');
			$lng = Yii::app()->request->getParam('lng');
			if (!empty($lat) and !empty($lng)) {
				//android/ios uses the reg_id to input registeration id for notification
				$device_notification_token = Yii::app()->request->getParam('reg_id');

				//get user id
				$hid = Yii::app()->request->getParam('hid');
				$key = Yii::app()->request->getParam('key');
				if (!empty($hid) and !empty($key)) {
					$id = $this->_auth($hid, $key);
				}
				
				//get user client language
				$lang = strtolower(Yii::app()->request->getParam('lang', 'en_gb'));

				$connection = Yii::app()->db;
				$sql_device = 'SELECT device_token, device_type, latitude, longitude FROM tbl_user_device_settings WHERE device_token=:device_token ';
				$command = $connection->createCommand($sql_device);
				$row = $command->queryRow(true, array(':device_token' => $token));
				if (empty($row)) {
					$sql_insert = 'INSERT INTO tbl_user_device_settings 
						(device_token, device_type, device_notification_token, latitude, longitude, id_user, lang, update_time, ip_address, agent)
						VALUES (:device_token, :device_type, :device_notification_token, :latitude, :longitude, :id_user, :lang, NOW(), :ip_address, :agent)';
					$params = array(
						':device_token' => $token,
						':device_type' => $device,
						':device_notification_token' => $device_notification_token,
						':latitude' => $lat,
						':longitude' => $lng,
						':id_user' => ($id < 10000) ? null : $id,
						':lang' => $lang,
						':ip_address' => Yii::app()->request->getUserHostAddress(),
						':agent' => Yii::app()->request->getUserAgent(),
					);
					$command = $connection->createCommand($sql_insert);
					$command->execute($params);
				} else {
					$params = array(
						':latitude' => $lat,
						':longitude' => $lng,
						':id_user' => ($id < 10000) ? null : $id,
						':lang' => $lang,
						':ip_address' => Yii::app()->request->getUserHostAddress(),
						':agent' => Yii::app()->request->getUserAgent(),
						':device_token' => $token,
					);
					
					//only update when there is reg_id
					$s_notification = '';
					if ($device_notification_token !== null) {
						$s_notification = ', device_notification_token=:device_notification_token ';
						$params[':device_notification_token'] = $device_notification_token;
					}
					//UPDATE device
					$sql_update = 'UPDATE tbl_user_device_settings 
						SET latitude=:latitude, longitude=:longitude, id_user=:id_user, lang=:lang, update_time=NOW(), ip_address=:ip_address, agent=:agent '
						. $s_notification .
						' WHERE device_token=:device_token ';
					$command = $connection->createCommand($sql_update);
					$command->execute($params);
				}
				
				//log the position for each API calling with device token. 2012.12.13
				$sql_logging = 'INSERT INTO tbl_user_device_logging (device_token, device_type, latitude, longitude, ip_address, agent)
						VALUES (:device_token, :device_type, :latitude, :longitude, :ip_address, :agent)';
				$command = $connection->createCommand($sql_logging);
				$command->execute(array(
					':device_token' => $token,
					':device_type' => $device,
					':latitude' => $lat,
					':longitude' => $lng,
					':ip_address' => Yii::app()->request->getUserHostAddress(),
					':agent' => Yii::app()->request->getUserAgent(),
				));
				
				$connection->active = false;
			}
		}
		
		self::APILogging('API', array(
			'URL' => Yii::app()->request->getUrl(),
			'POST' => $_POST,
			'GET' => $_GET
		), $token);
		
		return parent::beforeAction($action);
	}

	/**
	 * Authericate with hid + key.
	 * @param string $hid
	 * @param string $key
	 * @return int Merchant ID 
	 */
	protected function _auth($hid, $key) {
		if (empty($hid)) $this->_sendError('Parameter hid is missing!');
		if (empty($key)) $this->_sendError('Parameter key is missing!');
		$id = (int)BUtils::Decrypt($hid);
		if ($id < 10000) $this->_sendError('Authericate failed!');
		return $id;
	}
	
	protected function _getFacebookObject($access_token = null) {
		//1. init facebook API SDK
		require_once(Yii::app()->basePath . '/extensions/fbapi/facebook.php');
		$facebook = new Facebook(array(
			'appId'  => Yii::app()->params['facebook']['appId'],
			'secret' => Yii::app()->params['facebook']['secret'],
			'cookie' => false, // enable optional cookie support
		));
		if (!empty($access_token))
			$facebook->setAccessToken($access_token);
		return $facebook;
	}
	
	protected function _sendJSON($status, $message, $notify = null) {
		if (empty($notify)) {
			$json_string = array(
				'code' => $status,
				'message' => $message,
			);
		} else {
			$json_string = array(
				'code' => $status,
				'notify' => $notify,
				'message' => $message,
			);
		}
		$this->_sendResponse(200, CJSON::encode($json_string), 'application/json');
	}
	
	protected function _sendError($message) {
		$json_string = array(
			'code' => 500,
			'message' => $message,
		);
		$this->_sendResponse(200, CJSON::encode($json_string), 'application/json');
	}
	
	protected function _sendResponse($status = 200, $body = '', $content_type = 'application/json')
	{
		// set the status
		$status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);
		header($status_header);
		// and the content type
		header('Content-type: ' . $content_type);

		// pages with body are easy
		if ($body != '') {
			// send the body
			echo $body;
		}
		// we need to create the body if none is passed
		else
		{
			// create some body messages
			$message = '';

			// this is purely optional, but makes the pages a little nicer to read
			// for your users.  Since you won't likely send a lot of different status codes,
			// this also shouldn't be too ponderous to maintain
			switch($status)
			{
				case 401:
					$message = 'You must be authorized to view this page.';
					break;
				case 404:
					$message = 'The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found.';
					break;
				case 500:
					$message = 'The server encountered an error processing your request.';
					break;
				case 501:
					$message = 'The requested method is not implemented.';
					break;
			}

			// servers don't always have a signature turned on 
			// (this is an apache directive "ServerSignature On")
			$signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];

			// this should be templated in a real-world solution
			$body = array(
				'code' => $status,
				'status' => $this->_getStatusCodeMessage($status),
				'message' => $message,
				'signature' => $signature,
			);

			echo CJSON::encode($body);
		}
		Yii::app()->end();
	}
	
	/**
	 * get status message.
	 * @param int $status
	 * @return string 
	 */
	protected function _getStatusCodeMessage($status) {
		$codes = Array(
			100 => 'Continue',
			101 => 'Switching Protocols',
			200 => 'OK',
			201 => 'Created',
			202 => 'Accepted',
			203 => 'Non-Authoritative Information',
			204 => 'No Content',
			205 => 'Reset Content',
			206 => 'Partial Content',
			300 => 'Multiple Choices',
			301 => 'Moved Permanently',
			302 => 'Found',
			303 => 'See Other',
			304 => 'Not Modified',
			305 => 'Use Proxy',
			306 => '(Unused)',
			307 => 'Temporary Redirect',
			400 => 'Bad Request',
			401 => 'Unauthorized',
			402 => 'Payment Required',
			403 => 'Forbidden',
			404 => 'Not Found',
			405 => 'Method Not Allowed',
			406 => 'Not Acceptable',
			407 => 'Proxy Authentication Required',
			408 => 'Request Timeout',
			409 => 'Conflict',
			410 => 'Gone',
			411 => 'Length Required',
			412 => 'Precondition Failed',
			413 => 'Request Entity Too Large',
			414 => 'Request-URI Too Long',
			415 => 'Unsupported Media Type',
			416 => 'Requested Range Not Satisfiable',
			417 => 'Expectation Failed',
			500 => 'Internal Server Error',
			501 => 'Not Implemented',
			502 => 'Bad Gateway',
			503 => 'Service Unavailable',
			504 => 'Gateway Timeout',
			505 => 'HTTP Version Not Supported',
		);
		return (isset($codes[$status])) ? $codes[$status] : '';
	}
}